home *** CD-ROM | disk | FTP | other *** search
/ IRIX Installation Tools & Overlays 2001 November / SGI IRIX Installation Tools & Overlays 2001 November - Disc 1.iso / dist / roboinst.idb / usr / etc / roboinst_start.z / roboinst_start
Text File  |  2001-10-10  |  41KB  |  1,553 lines

  1. #! /bin/sh
  2. #Tag 0x00000f00
  3. #ident "$Revision $"
  4.  
  5. # Copyright 1997-2000, Silicon Graphics, Inc.
  6. # All Rights Reserved.
  7. #
  8. # This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  9. # the contents of this file may not be disclosed to third parties, copied or
  10. # duplicated in any form, in whole or in part, without the prior written
  11. # permission of Silicon Graphics, Inc.
  12. #
  13. # RESTRICTED RIGHTS LEGEND:
  14. # Use, duplication or disclosure by the Government is subject to restrictions
  15. # as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  16. # and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  17. # successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  18. # rights reserved under the Copyright Laws of the United States.
  19.  
  20. # roboinst_start
  21. #
  22. # Do not run this script directly.  See roboinst(1M) for details.
  23. #
  24. # This script verifies that roboinst configuration information is
  25. # available, then restarts the system in roboinst mode or runs live.
  26. #
  27. # In miniroot mode (standard) it checks to see if the sa bootfile in
  28. # the specified bootdir can be read, then attempts to download the
  29. # custom configuration information.  The mrconfig file is parsed for
  30. # loghost, and the roboinst checkpoint file is written in /var/inst.
  31. # The volume header is then poked, and the machine is rebooted, with
  32. # nvram mrmode set to either custom or customdebug.
  33. #
  34. # In live mode it attempts to download the custom configuration
  35. # information and starts a live roboinst session.
  36.  
  37. usage="error: please use roboinst(1M)"
  38.  
  39. PATH=/sbin:/usr/bin:/usr/bsd:/usr/sbin:/etc:/usr/etc:
  40.  
  41. umask 022
  42.  
  43. test "$TMPDIR" = "" && {
  44.     TMPDIR=/tmp
  45.     export TMPDIR
  46. }
  47.  
  48. INSTRBASE=
  49. CHECKPOINT=/var/inst/.roboinst_status
  50. BPCLT=/usr/etc/bootpc
  51. GETHOSTBYNAME=/usr/etc/gethostbyname
  52. SYSLOGCONF=/etc/syslog.conf
  53. CUSTOM=$TMPDIR/d.roboinst.$$
  54. MRCONF=mrconfig
  55. MRCONFIG=$CUSTOM/$MRCONF
  56. MREXPORTS=$CUSTOM/$MRCONF.exports
  57. INDEXFILE=.index
  58. LOGOK="nologmsg ok"
  59. ERROR="nologmsg error"
  60. WARNING="nologmsg warning"
  61. INFO="nologmsg info"
  62. DEBUG=":"
  63. ROBOINSTLOG=/var/inst/.roboinstlog
  64. DBGFD=-
  65. LOGGER="logger -t roboinst"
  66. TMPFILE=$TMPDIR/roboinst.$$
  67. TMPROOT=$TMPDIR/roboroot.$$
  68. ECHO=echo
  69. # The highest version of mrconfig we understand.
  70. # DEFVERS is assumed if mrconfig contains no "version" keyword.
  71. MAXVERS=1
  72. DEFVERS=1
  73. # The RoboInst version number, to manage updates:
  74. VERSION="1.1"
  75.  
  76. msgfile=uxsgicore
  77. #    Check the user id.
  78. if [ -x /usr/bin/id ]; then
  79.     eval `/usr/bin/id  |  sed 's/[^a-z0-9=].*//'`
  80.     if [ "${uid:=0}" -ne 0 ]; then
  81.     printf "`gettxt ${msgfile}:710 '%s:  Only root can run /etc/shutdown.'`\n" $0
  82.     exit 2
  83.     fi
  84. fi
  85.  
  86. #
  87. # Process options and arguments
  88. #
  89. confirmation=""
  90. timestr=""
  91. bootdir=""
  92. configdir=""
  93. debugmode=""
  94. disksetup=""
  95. syspart=""
  96. grace="60"
  97. livemode=""
  98. reportaddr=""
  99. netmode=""
  100. versiononly=""
  101. emailaddr=""
  102. while getopts b:c:dg:Lm:nN:pP:st:V:yqz OPT; do
  103.     case $OPT in
  104.     b)  bootdir="$OPTARG";;
  105.     c)  configdir="$OPTARG";;
  106.     d)  DEBUG=echo; DBGFD=1; debugmode=debug;;
  107.     g)  grace="$OPTARG";;
  108.     L)  livemode=yes;;
  109.     m)  emailaddr="$OPTARG";;
  110.     n)  confirmation=no;;
  111.     N)  netmode="$OPTARG";;
  112.     p)  syspart=yes;;
  113.     P)  syspart="$OPTARG";;
  114.     s)  disksetup=disksetup;;
  115.     t)  timestr="$OPTARG";;
  116.     V)  versiononly="$OPTARG";;
  117.     y)  confirmation=yes;;
  118.     z)  reportaddr=yes;;
  119.     q)  ECHO=:;;
  120.     *)  echo $usage; exit 2
  121.     esac
  122. done
  123.  
  124. if [ "$versiononly" = "0" ] ; then
  125.     echo $VERSION
  126.     exit 0
  127. elif [ "$versiononly" != "" ] ; then
  128.     expr "$versiononly" ">=" "$VERSION" >/dev/null
  129.     exit $?
  130. fi
  131.  
  132. if [ "$configdir" = "" ]; then
  133.     echo $usage
  134.     exit 2
  135. fi
  136. if [ "$bootdir" = "" -a "$livemode" = "" ]; then
  137.     echo $usage
  138.     exit 2
  139. fi
  140.  
  141. # configdhcp contains the possible dhcp mode: [%!+]
  142. case $netmode in
  143.     local|LOCAL|none|NONE) configdhcp='!' ;;
  144.     bootp*|BOOTP*|*1533) configdhcp='%' ;;
  145.     dhcp|DHCP)    configdhcp='+'    ;;
  146.     *)    configdhcp="" ;;
  147. esac
  148.  
  149. #
  150. # ---- define some functions ----
  151. #
  152.  
  153. # I18N
  154. # ----------------------------------------------------------------------------
  155. ask() {
  156. #! ask msg default
  157. #!  default should be 0 for "no", "yes" otherwise
  158. #!  returns 0 for "no", otherwise "yes"
  159.  
  160.     yesstr=`gettxt ${msgfile}:171 "yes"`
  161.     nostr=`gettxt ${msgfile}:172 "no"`
  162.     choicefmt=`gettxt ${msgfile}:169 "(%s/%s)"`
  163.     defaultfmt=`gettxt ${msgfile}:170 "[%s]"`
  164.     shortyes=`echo $yesstr | cut -c1`
  165.     shortno=`echo $nostr | cut -c1`
  166.  
  167.     fmt=${choicefmt}${defaultfmt}
  168.     if [ $2 -eq 0 ]; then
  169.     str=`printf "${choicefmt}${defaultfmt} : " "$yesstr" "$nostr" "$nostr"`
  170. else
  171.     str=`printf "${choicefmt}${defaultfmt} : " "$yesstr" "$nostr" "$yesstr"`
  172.     fi
  173.     printf "%s%s" "$1" "$str"
  174.  
  175.     read ans
  176.  
  177. # convert answer to lowercase
  178.     ans=`echo $ans | tr '[A-Z]' '[a-z]'`
  179.  
  180.     case "$ans" in
  181.     ${yesstr}*)    ret=1
  182.             ;;
  183.     ${nostr}*)    ret=0
  184.             ;;
  185.     ${shortyes}*)    ret=1
  186.             ;;
  187.     ${shortno}*)    ret=0
  188.             ;;
  189.     *)        ret=$2
  190.             ;;
  191.     esac
  192.  
  193.     return ${ret}
  194. } # End of ask
  195.  
  196. msgfile=uxsgicore
  197. # ----------------------------------------------------------------------------
  198.  
  199. #
  200. # the following functions are copied wholesale from
  201. # eoe/cmd/initpkg/mrcustomrc.sh so that changes should be mirrored
  202. # in both places
  203. #
  204.  
  205. #------- functions copied from eoe/cmd/initpkg/mrcustomrc.sh --------
  206.  
  207. # Send a log message to various places
  208.  
  209. logmsg()
  210. {
  211.     if [ "$1" = "ok" ]; then
  212.         shift 2>/dev/null ; mstate="$1" ; shift 2>/dev/null
  213.         msg="state=$mstate status=0 $*"
  214.     elif [ "$1" = "error" ]; then
  215.         shift 2>/dev/null ; mstate="$1" ;
  216.         shift 2>/dev/null ; mstatus="$1" ; shift 2>/dev/null
  217.         msg="state=$mstate status=$mstatus error: $*"
  218.     elif [ "$1" = "warning" ]; then
  219.         shift 2>/dev/null
  220.     msg="warning: $*"
  221.     elif [ "$1" = "info" ]; then
  222.         shift 2>/dev/null
  223.     msg="$*"
  224.     else
  225.         msg="$*"
  226.     fi
  227.  
  228.     $LOGGER "$msg"
  229.     echo "roboinst: $msg"
  230.     if [ -f $ROBOINSTLOG ]; then
  231.         # queue remote msgs until loghost is known
  232.     echo "$msg" >> $ROBOINSTLOG
  233.     fi
  234. }
  235.  
  236. # Generate statements of the form:  "A=val ; export A ; B=val ; export B ; "
  237. # to represent SGI_CAPACITY and SGI_CAP_<device>
  238.  
  239. disk_capacity()
  240. {
  241.     # Set SGI_CAP_<device>
  242.     (cd /dev/scsi && ls -1|grep '^sc'|xargs -n10 scsicontrol -c \
  243.        | sed -n 's/^sc\([0-9]*\)d\([0-9]*\)l\([0-9]*\):.*capacity=\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*/SGI_CAP_dks\1d\2vol=\4 ; export SGI_CAP_dks\1d\2vol ; /p')
  244.  
  245.     # Set SGI_CAPACITY for root device
  246.  
  247.     ( cd /dev/rdsk && \
  248.       rootdev=`stat -rq root` && \
  249.       test "$rootdev" && \
  250.           for f in dks* ; do
  251.           test "$f" && \
  252.           test "`stat -rq $f`" = "$rootdev" && {
  253.               ff=`echo $f|sed -n 's/^dks\([0-9]*\)d\([0-9]*\)s\([0-9]*\)/dks\1d\2/p'`
  254.               echo "SGI_CAPACITY=\$SGI_CAP_${ff}vol ; export SGI_CAPACITY ; "
  255.               break;
  256.           }
  257.       done )
  258. }
  259.  
  260. # Build the export file $MREXPORTS.  This holds environment
  261. # variables that will be exported over the course of the miniroot
  262. # session.  We only construct the file once, then . it in later
  263. # invocations of mrcustomrc.
  264.  
  265. build_exports()
  266. {
  267.     inst -H > $TMPFILE 2>&-
  268.     SGI_CPUBOARD=`sed -n 's/^CPUBOARD=//p' $TMPFILE`
  269.     SGI_CPUARCH=`sed -n 's/^CPUARCH=//p' $TMPFILE|grep -iv MIPS`
  270.     SGI_VIDEO=`sed -n 's/^VIDEO=//p' $TMPFILE`
  271.     SGI_ABI=`sed -n 's/^CPUARCH=//p' $TMPFILE|grep -i MIPS`
  272.     SGI_GFXBOARD=`sed -n 's/^GFXBOARD=//p' $TMPFILE`
  273.     SGI_SUBGR=`sed -n 's/^SUBGR=//p' $TMPFILE`
  274.     SGI_MODE=`sed -n 's/^MODE=//p' $TMPFILE`
  275.     SGI_MACHINE=`sed -n 's/^MACHINE=//p' $TMPFILE`
  276.     rm -f $TMPFILE 2>&-
  277.  
  278.     SGI_ROOT=$INSTRBASE
  279.     SGI_CUSTOM=$CUSTOM
  280.     SGI_SYSID="$chaddr"
  281.     SGI_IPADDR="$netaddr"
  282.     SGI_HOSTNAME=`sed -n p /etc/sys_id 2>&-`
  283.     SGI_MEMSIZE=`hinv | sed -n 's/.*Main memory size: \([0-9]*\) Mbytes.*/\1/p'`
  284.  
  285.     bootfile="$bootdir"
  286.     SGI_BOOTSERVER=`echo "$bootfile" | sed -n 's;:.*;;p'`
  287.     SGI_BOOTDIR=`echo "$bootfile" | sed -e 's;.*:;;' -e 's;^/sa$;/;' -e 's;/sa;;' -e 's;^sa$;.;'`
  288.  
  289.     # default is to use DHCP, so that empty $configdir does the right thing
  290.     # NOTE: this check is in multiple locations!
  291.     #       see also mrcustomrc in the miniroot
  292.     case "$configdhcp" in
  293.     !*)
  294.         # don't do any DHCP stuff
  295.         SGI_NETINQUIRY="NONE"
  296.         ;;
  297.     +*)
  298.         # DHCP assignes IP address if it is available
  299.         SGI_NETINQUIRY="DHCP"
  300.         ;;
  301.     %*|*)
  302.         # use extended BOOTP protocol
  303.         # (use IP address from nvram, but ask for network parameters)
  304.         SGI_NETINQUIRY="BOOTP1533"
  305.         ;;
  306.     esac
  307.  
  308.     SGI_CONFIGSERVER=`echo "$configdir" | sed -n 's;:.*;;p'`
  309.     SGI_CONFIGDIR=`echo "$configdir" | sed -e 's;.*:;;'`
  310.  
  311.     SGI_SYSTEMPART=`devnm / | sed 's/. .*/0/'`
  312.     SGI_SYSTEMDISK=`echo "$SGI_SYSTEMPART" | sed 's/s[0-9]*$//'`
  313.     rm -f $MREXPORTS 2>&-
  314.  
  315.     ( for var in SGI_CPUBOARD SGI_GFXBOARD SGI_SUBGR SGI_VIDEO \
  316.         SGI_CPUARCH SGI_ABI SGI_MODE SGI_MACHINE \
  317.         SGI_ROOT SGI_CUSTOM \
  318.         SGI_SYSID SGI_IPADDR SGI_HOSTNAME \
  319.         SGI_BOOTSERVER SGI_BOOTDIR SGI_CONFIGSERVER SGI_CONFIGDIR \
  320.         SGI_SYSTEMPART SGI_SYSTEMDISK \
  321.         SGI_MEMSIZE SGI_NETINQUIRY ; do
  322.     eval "echo \"\$$var\"" | \
  323.         sed -e 's/"/\\"/g' \
  324.         -e 's/\(.*\)/'$var'="\1"; export '$var'/'
  325.       done
  326.       disk_capacity 2>&-
  327.     ) > $MREXPORTS
  328. }
  329.  
  330. # tftp remote file ($1) to local file ($2) using
  331. # mode ($3).  Suppress msg if quiet is 1 ($4).
  332.  
  333. dotftp()
  334. {
  335.     tstat=0
  336.     if [ "$3" != "" ]; then
  337.     MODE=$3
  338.     else
  339.     MODE=binary
  340.     fi
  341.     test "$4" != 1 && $DEBUG tftp $1 $2
  342.     tftp <<- EOF >$TMPFILE 2>&1
  343.         mode $MODE
  344.         get $1 $2
  345.         quit
  346.     EOF
  347.     test "$?" != 0 -o ! -f "$2" && {
  348.     cat $TMPFILE
  349.     tstat=1
  350.     }
  351.  
  352.     rm -f $TMPFILE >/dev/null 2>&1
  353.     return $tstat
  354. }
  355.  
  356. # test whether a file ($1) has the expected size ($2)
  357.  
  358. chksize()
  359. {
  360.     test "$2" = "" && return 0
  361.     s=`/sbin/stat -qs $1`
  362.     test "$s" != "$2" && \
  363.     { $ERROR init 1 "Size mismatch for $1 $s (expected $2)";
  364.       $ERROR init 1 "Try re-running roboinst_config on the configuration directory";
  365.       return 1; }
  366.     return 0
  367. }
  368.  
  369. # test whether a file ($1) has the expected checksum ($2)
  370.  
  371. chksum()
  372. {
  373.     test "$2" = "" && return 0
  374.     s=`sum -r $1 | nawk '{print $1}'`
  375.     test "$s" != "$2" && \
  376.     { $ERROR init 1 "Checksum mismatch for $1 $s (expected $2)";
  377.       $ERROR init 1 "Try re-running roboinst_config on the configuration directory";
  378.       return 1; }
  379.     return 0
  380. }
  381.  
  382. # $1 = remote pathname, $2 = local pathname, $3 = tftp(0)/rcp(1), $4= attrs
  383.  
  384. filecopy()
  385. {
  386.     type=""
  387.     size=""
  388.     sum=""
  389.     mode=""
  390.  
  391.     # parse valid attrs into local vars
  392.     eval ` echo "$4" | \
  393.        nawk \
  394.     ' { for (i=1; i <= NF; ++i)
  395.           if (match($i,"^size=")) {
  396.          s=substr($i,RSTART+RLENGTH,length($i)-RLENGTH);
  397.          if (match(s,"^[0-9][0-9]*$"))
  398.             printf("size=%s;",s);
  399.           } else if (match($i,"^sum=")) {
  400.          s=substr($i,RSTART+RLENGTH,length($i)-RLENGTH);
  401.          if (match(s,"^[0-9][0-9]*$"))
  402.             printf("sum=%s;",s);
  403.           } else if (match($i,"^type=")) {
  404.              s=substr($i,RSTART+RLENGTH,length($i)-RLENGTH);
  405.          if (match(s,"^[fd]*$"))
  406.             printf("type=%s;",s);
  407.           } else if (match($i,"^mode=")) {
  408.          s=substr($i,RSTART+RLENGTH,length($i)-RLENGTH);
  409.          if (match(s,"^[0-7][0-7]*$"))
  410.             printf("mode=%s;",substr(s,length(s)-3,3));
  411.           }
  412.         } ' `
  413.  
  414.     if [ "$type" = "" -o "$type" = "f" ]; then
  415.  
  416.     if [ $3 -eq 0 ]; then
  417.         dotftp $1 $2
  418.     else
  419.         rcp -v $1 $2 >&$DBGFD 2>&$DBGFD
  420.     fi
  421.  
  422.     ( test $? -eq 0 &&
  423.       chksize $2 $size &&
  424.       chksum $2 $sum &&
  425.       chmod $mode $2 ) || return 1
  426.  
  427.     elif [ "$type" = "d" ]; then
  428.  
  429.     $DEBUG mkdir $2
  430.  
  431.     ( mkdir -p $2 &&
  432.       chmod $mode $2 ) || return 1
  433.  
  434.     else
  435.  
  436.     $ERROR init 1 "Unknown filetype $type"
  437.     return 1
  438.  
  439.     fi
  440.     return 0
  441. }
  442.  
  443. # $1 = remote dir (from), $2 = local dir (to), $3 = tftp(0) or rcp(1)
  444.  
  445. dircopy()
  446. {
  447.     mkdir -p $2 || return 1
  448.     rm -f $2/$INDEXFILE >/dev/null 2>&1
  449.     if [ $3 -eq 0 ]; then
  450.     dotftp $1/$INDEXFILE $2/$INDEXFILE ascii 1
  451.     else
  452.     rcp -v $1/$INDEXFILE $2/$INDEXFILE >&$DBGFD 2>&$DBGFD
  453.     fi
  454.     ( test $? -eq 0 && test -s $2/$INDEXFILE) || {
  455.     $DEBUG "dircopy: no index file $1/$INDEXFILE"
  456.     rm -f $2/$INDEXFILE >/dev/null 2>&1  # in case it was empty
  457.  
  458.     if [ $3 -eq 0 ]; then
  459.         dotftp $1/$MRCONF $2/$MRCONF ascii 1
  460.     else
  461.         rcp -v $1/$MRCONF $2/$MRCONF >&$DBGFD 2>&$DBGFD
  462.     fi
  463.  
  464.     ( test $? -eq 0 && test -s $2/$MRCONF) || {
  465.         $DEBUG "dircopy: no configuration file $1/$MRCONF"
  466.         rm -f $2/$MRCONF >/dev/null 2>&1  # in case it was empty
  467.         return 1
  468.     }
  469.  
  470.     return 0
  471.     }
  472.     ( ret=0;
  473.       while read pathname attrs ; do
  474.         echo "$pathname" | grep '^#' >/dev/null || \
  475.         filecopy $1/$pathname $2/$pathname $3 "$attrs" || ret=1
  476.       done;
  477.       return $ret ) < $2/$INDEXFILE || return 1
  478.  
  479.     return 0
  480. }
  481.  
  482. # Copy the remote scripts ($1) to a local dir ($2),
  483. # $3 is the hardware address, and $4 is the IP address
  484. # ($3 and $4 and not currently used.)
  485.  
  486. getcustom()
  487. {
  488.     remote="$1"
  489.     local="$2"
  490.  
  491.     $DEBUG "getcustom $1 $2 $3 $4"
  492.  
  493.     for src in $remote
  494.     do
  495.     rm -fr $local >/dev/null 2>&1
  496.     dircopy $src $local 0 && {
  497.         $LOGOK custom "using configuration $src"
  498.         return 0
  499.         }
  500.     done
  501.  
  502.     echo "$remote" | grep "^.*@.*:" > /dev/null || \
  503.     remote="guest@$remote"
  504.  
  505.     for src in $remote
  506.     do
  507.     rm -fr $local >/dev/null 2>&1
  508.     dircopy $src $local 1 && {
  509.         $LOGOK custom "using configuration $src"
  510.         return 0
  511.         }
  512.     done
  513.  
  514.     rm -fr $local >/dev/null 2>&1
  515.  
  516.     return 1
  517. }
  518.  
  519. # Preprocess the setenv and if/then/else conditionals
  520. # in the mrconfig file, and generate separate files such
  521. # as /custom/mrconfig.preinst for each phase.
  522.  
  523. preprocess()
  524. {
  525.     test -f $MRCONFIG && \
  526.     nawk -v p=1 -v top=-1 -v cfg=$MRCONFIG \
  527.     'function unexpected(kwd,line)
  528.      { printf "ERROR: unexpected \"%s\" keyword at line %d\n", kwd, line; }
  529.  
  530.      BEGIN { # the files for these phases are written
  531.          # raw, without the #!/bin/sh heading and
  532.          # opening environment section.
  533.              special["partition"] = 1;
  534.              special["onerror"] = 1;
  535.              special["loghost"] = 1;
  536.              special["version"] = 1;
  537.              special["nokernel"] = 1;
  538.              special["inst"] = 1;
  539.          # for these phases, write a separate side-file
  540.          # that contains the environment.
  541.              sepenv["inst"] = 1;
  542.          # slines[scount] is an array containing all
  543.          # the setenv commands we have seen thus far.
  544.          scount =0;
  545.          # name of temp file for variable expansions
  546.          srand;
  547.          envfile = "/tmp/roboenv" rand;
  548.            }
  549.     {  if (match($1, "^#")) {
  550.         next;
  551.        } else if ($1 == "if") {
  552.         sub($1,"",$0);
  553.         if ($NF == "then")
  554.             sub("then[ \t]*$","",$0);
  555.         t = p ? system(envargs " " $0) : 0;
  556.         pstack[++top] = p;
  557.         ifstack[top] = "if";
  558.         tstack[top] = t;
  559.         p = p && (t == 0);
  560.         next;
  561.        } else if ($1 == "elsif" || $1 == "elif") {
  562.         if (ifstack[top] != "if" && ifstack[top] != "elsif")
  563.             { unexpected($1, FNR); next; }
  564.         sub($1,"",$0);
  565.         if ($NF == "then")
  566.             sub("then[ \t]*$","",$0);
  567.         ifstack[top] = "elsif";
  568.         if ((top < 0 || pstack[top]) && tstack[top] != 0)
  569.             t = system(envargs " " $0);
  570.         else
  571.             t = 1;
  572.         if (tstack[top] == 0)
  573.             t = 1;
  574.         else
  575.             tstack[top] = t;
  576.         p = (top < 0 || pstack[top]) && (t == 0);
  577.         next;
  578.        } else if ($1 == "else") {
  579.         if (ifstack[top] != "if" && ifstack[top] != "elsif")
  580.             { unexpected($1, FNR); next; }
  581.         ifstack[top] = "else";
  582.         p = (top < 0 || pstack[top]) && (tstack[top] != 0);
  583.         next;
  584.        } else if ($1 == "endif" || $1 == "fi") {
  585.         if (ifstack[top] != "if" && ifstack[top] != "elsif" && ifstack[top] != "else")
  586.             { unexpected($1, FNR); next; }
  587.         p = pstack[top--];
  588.         next;
  589.        }
  590.        if (!p) next;
  591.        if (match($1, "setenv>?") && length($2) > 0) {
  592.            # expand the envargs string for later use in
  593.            # this nawk script (when we run condition
  594.            # subprocesses above), and also save the environment
  595.            # setting in the file mrconfig.setenv.
  596.            var = $2;
  597.            val = $0;
  598.            sub("^[ \t]*setenv>?[ \t]+" var "[ \t]*", "", val);
  599.            if (!match(val, "^[A-Za-z0-9_\.\-]*$")) {
  600.            # do shell expansion
  601.            syscmd=sprintf(envargs " echo %s > %s", val, envfile);
  602.            system(syscmd);
  603.            getline val < envfile;
  604.            close(envfile);
  605.            }
  606.            ENVIRON[var] = val;
  607.            gsub("\"", "\\\"", val);
  608.            envargs = envargs var "=\"" val "\" ; export " var " ; ";
  609.            outfile = cfg ".setenv";
  610.            setcmd = sprintf ("%s=\"%s\"; export %s", var, val, var);
  611.            printf "%s\n", setcmd > outfile;
  612.            slines[scount++] = setcmd;
  613.        } else if (NF > 0) {
  614.            # save this line in corresponding output file
  615.            line = $0;
  616.            phase = $1;
  617.            sub(">$","",phase);
  618.            outfile = cfg "." phase;
  619.            if (!seenfile[phase]) {
  620.            seenfile[phase] = 1;
  621.            if (!special[phase]) {
  622.                # unless this phase is 'special', write the
  623.                # interpreter line, and any lines from the
  624.                # mrconfig.setenv file we have accumulated thus far.
  625.                printf "#!/bin/sh\n" > outfile
  626.                for (s=0; s<scount; ++s)
  627.                    printf "%s\n", slines[s] > outfile;
  628.                system("chmod 755 " outfile);
  629.            }
  630.            if (sepenv[phase]) {
  631.                # some phases needed a separate environment file
  632.                # so remember the current contents of mrconfig.setenv
  633.                # as mrconfig.setenv.inst, for example.
  634.                system("cp " cfg ".setenv " cfg ".setenv." phase " 2>&-");
  635.            }
  636.            }
  637.            sub("^[ \t]*" phase ">?($|[ \t])", "", line);
  638.            if (special[phase]) {
  639.            # do envvar substitution for phases that
  640.            # are not interpreted by /bin/sh
  641.            while (1) {
  642.                if (match(line, "^\\$[A-Za-z_]+"))
  643.                ;
  644.                else if (match(line, "[^\\\\]\\$[A-Za-z_]+"))
  645.                { RSTART += 1; RLENGTH -=1 }
  646.                else
  647.                break;
  648.                line = substr(line,1,RSTART-1) \
  649.                   ENVIRON[substr(line, RSTART+1, RLENGTH-1)] \
  650.                   substr(line,RSTART+RLENGTH,length(line));
  651.            }
  652.            }
  653.            if (phase == "partition") {
  654.            # substitute systemdisk keywords in partition statements
  655.            w="";
  656.            if (match(line, "^[ \t]*")) w=substr(line, RSTART, RLENGTH);
  657.            if (sub("^[ \t]*systemdisk", "", line)) {
  658.                # if partition was omitted assume 0
  659.                if (match(line, "^[0-9]|^vh|^vol"))
  660.                line = w ENVIRON["SGI_SYSTEMDISK"] "s" line;  # dks0d1 + s + line
  661.                else
  662.                line = w ENVIRON["SGI_SYSTEMPART"] line;      # dks0d1s0
  663.            }
  664.            }
  665.            printf "%s\n", line > outfile;
  666.        }
  667.      }
  668.      END { system(sprintf("rm %s 2>&-", envfile)) }' $MRCONFIG
  669. }
  670.  
  671.  
  672.  
  673.  
  674. # Derive the fstab from the partition statements in the mrconfig
  675. # file, and print results on stdout
  676.  
  677. buildfstab()
  678. {
  679.     nawk ' { if ($3 != "swap" && $4 != "nomount") {
  680.            dev = match($1,"^/") ? $1 : "/dev/dsk/" $1;
  681.            type = $3;
  682.            dir = $4;
  683.            sub("/.*","",type);
  684.            if (type == "option" || type == "root")
  685.                type = "xfs";
  686.            if (type != "xfs" && type != "nfs" && type != "efs")
  687.            next;
  688.            opt = ""
  689.            # optional mount options are terminated
  690.            # by optional semicolon.
  691.            for (i=5; i <= NF && $i != ";"; ++i)
  692.            if (opt == "")
  693.                opt = $i;
  694.            else
  695.                opt = opt " " $i;
  696.            if (opt == "") {
  697.                if (type == "nfs") {
  698.               opt="ro,soft,bg"
  699.            } else {
  700.               rdev=dev;
  701.               sub("^/dev/dsk", "/dev/rdsk", rdev);
  702.               opt = "rw,raw=" rdev;
  703.           }
  704.            }
  705.            if (dir != "")
  706.            printf "%s %s %s %s 0 0\n", dev, dir, type, opt;
  707.          }
  708.        } ' $MRCONFIG.partition 2>&-
  709. }
  710.  
  711.  
  712.  
  713. # Run user sh commands in the mrconfig file labeled with
  714. # pattern ($1).  Additional args ($2, $3, ...) are passed
  715. # as positional parameters.
  716.  
  717. runuser()
  718. {
  719.     phase=$1
  720.     runfile=$MRCONFIG.$phase
  721.     shift
  722.     if [ -x $runfile ]; then
  723.     $runfile $*
  724.     istat=$?
  725.     if [ $istat = 0 ]; then
  726.         $LOGOK $phase ok
  727.     else
  728.         $ERROR $phase "$istat" "failed"
  729.     fi
  730.     fi
  731. }
  732.  
  733.  
  734. #------- end of functions from mrcustomrc.sh --------
  735.  
  736. #------- begin other functions --------
  737.  
  738. # get the IP address for a given host ($1)
  739. # returns the IP address in IPADDR global variable
  740. # returns 1 if got a name
  741.  
  742. getipaddr()
  743. {
  744.     hostname="$1"
  745.  
  746.     if [ ! -x $GETHOSTBYNAME ]; then
  747.     $ERROR init 1 "$GETHOSTBYNAME not installed, unable to lookup $hostname"
  748.     exit 1
  749.     fi
  750.  
  751.     IPADDR=`$GETHOSTBYNAME $hostname | \
  752.         nawk -v a=0 '/^'$hostname' / { a=$3; exit }
  753.                     END      { print a }'`
  754.  
  755.     test "$IPADDR" != "0" && return 0
  756.  
  757.     return 1
  758. }
  759.  
  760.  
  761. #------- begin functions for live roboinst -------
  762.  
  763. # add a host or hosts to the syslog
  764.  
  765. syslog_addhost()
  766. {
  767.     tmp1=$SYSLOGCONF.1.$$
  768.     tmp2=$SYSLOGCONF.2.$$
  769.     
  770.     getipaddr `hostname`
  771.     thisip=$IPADDR
  772.  
  773.     cp $SYSLOGCONF $tmp1
  774.  
  775.     for host in $* ;  do
  776.     (   if [ "$host" = "localhost" ]; then
  777.         IPADDR=$thisip
  778.         else
  779.         getipaddr $host
  780.         fi
  781.         grep -v '@'$IPADDR'[^-a-zA-Z0-9_.]?' $tmp1
  782.         if [ "$thisip" != "$IPADDR" ]; then
  783.         echo '## remote loghost @'$IPADDR' ##'
  784.         echo 'kern.debug\t|/usr/sbin/klogpp\t@'$IPADDR
  785.         echo '*.debug;kern.none\t@'$IPADDR
  786.         echo '## done loghost @'$IPADDR' ##'
  787.         fi ) >$tmp2 2>/dev/null
  788.     mv $tmp2 $tmp1
  789.     done
  790.  
  791.     if [ -s $tmp1 ]; then
  792.  
  793.     # save original for syslog_restore()
  794.     mv $SYSLOGCONF $SYSLOGCONF.$$
  795.  
  796.     # move new file into place
  797.     mv $tmp1 $SYSLOGCONF
  798.  
  799.     killall -HUP syslogd
  800.     fi
  801.     rm -f $tmp1 $tmp2 2>/dev/null
  802. }
  803.  
  804. # restore original syslog configuration
  805.  
  806. syslog_restore()
  807. {
  808.     if [ -s $SYSLOGCONF.$$ ]; then
  809.         rm -f $SYSLOGCONF 2>/dev/null
  810.     mv $SYSLOGCONF.$$ $SYSLOGCONF
  811.     killall -HUP syslogd
  812.     fi
  813. }
  814.  
  815. # returns the name of the builtin ethernet interface, the one that the PROM
  816. # and miniroot will use (first).
  817. # (mostly copied from mrnetrc, which is derived from init.d/network)
  818.  
  819. defaultinterface()
  820. {
  821.     hinv -c network | sed -ne 's/^Integr.* \([a-z][a-z]*0\),.*$/\1/p'
  822. }
  823.  
  824. get_config()
  825. {
  826.     # get net address and netmask of PROM boot interface
  827.  
  828.     promif=`defaultinterface`
  829.     ifstr=`ifconfig $promif`
  830.     ifup=`echo $ifstr | grep UP`
  831.     if [ -z "$ifup" -a "$livemode" != "yes" ] ; then
  832.     $ERROR init 1 "Miniroot boot interface $promif is not active, aborting"
  833.     exit 1
  834.     fi
  835.     netaddr=`echo $ifstr | nawk '{
  836.     for(i=1; i<NF; ++i) {
  837.         if ($i ~ /inet/){print $(i+1);}
  838.     }}'`
  839.     netmask=`echo $ifstr | nawk '{
  840.     for(i=1; i<NF; ++i) {
  841.         if ($i ~ /netmask/){print $(i+1);}
  842.     }}'`
  843.     $DEBUG "Assuming current IP address $netaddr, netmask $netmask"
  844.     chaddr=`/usr/etc/netstat -ian -I $promif | nawk '/:/ {print $1}'`
  845.  
  846.     # copy the client configuration directory, check attributes
  847.  
  848.     getcustom "$configdir" $CUSTOM "$chaddr" "$netaddr"
  849.  
  850.     if [ ! -d $CUSTOM ]; then
  851.     $ERROR custom 3 "unable to retrieve configuration from $configdir"
  852.     exit 1
  853.     fi
  854.  
  855.     # Compute the values of the SGI_ roboinst variables once,
  856.     # and store them in a file for use during the remainder
  857.     # of the miniroot session.
  858.     build_exports
  859.     test -s $MREXPORTS && . $MREXPORTS
  860.  
  861.     # pre-process the mrconfig file to create a series
  862.     # of mrconfig.<phase> files that are access later in
  863.     # the miniroot session.
  864.     preprocess
  865.  
  866.     # Verify that we understand this version of mrconfig
  867.     mrversion=`nawk '{ if ($1 != "") { print $1; exit } }' $MRCONFIG.version 2>&-`
  868.     if [ "$mrversion" = "" ]; then
  869.         mrversion=$DEFVERS
  870.     fi
  871.  
  872.     $DEBUG mrversion $mrversion
  873.  
  874.     if [ "$mrversion" -gt $MAXVERS ]; then
  875.         rm -rf $CUSTOM 2>&-
  876.     $ERROR custom 4 "mrconfig with invalid version $mrversion."
  877.     $ERROR custom 4 "This version of roboinst only understands versions up through $MAXVERS."
  878.     exit 1
  879.     fi
  880. }
  881.  
  882. # Initialize, fetch contents of /custom directory.
  883.  
  884. startcustom()
  885. {
  886.     # Log the fact that we've reached miniroot state.
  887.     $LOGOK live "retrieving configuration"
  888.  
  889.     # get the configuration files
  890.  
  891.     get_config
  892.  
  893.     # is this a dry run?
  894.  
  895.     if [ "$confirmation" = "no" ]; then
  896.     $INFO "Automatic installation canceled"
  897.     exit 1
  898.     fi
  899.  
  900.     # Start remote logging if requested
  901.  
  902.     loghost=`cat $MRCONFIG.loghost 2>&-`
  903.     if [ "$loghost" != "" ]; then
  904.     $INFO "loghost $loghost"
  905.     syslog_addhost $loghost
  906.     fi
  907.  
  908.     # Log the fact that we've actually begun processing.
  909.     $LOGOK live "beginning processing"
  910.  
  911.     # We are done with the initial processing.
  912.     # Run user init commands immediately.
  913.     runuser init
  914. }
  915.  
  916. # live roboinst processing
  917.  
  918. runlive()
  919. {
  920.     # Scripts catch but no-op SIGINT (from ^C) so that they
  921.     # are not disrupted by user hitting ^C, but still allow
  922.     # any subshells to default SIGINT.  Ditto SIGQUIT (3), I guess.
  923.  
  924.     trap : 2 3
  925.  
  926.     LOGOK="logmsg ok"
  927.     ERROR="logmsg error"
  928.     WARNING="logmsg warning"
  929.     INFO="logmsg info"
  930.  
  931.     #
  932.     # phase: start
  933.     #
  934.  
  935.     startcustom
  936.  
  937.     #
  938.     # phase: preinst
  939.     #
  940.  
  941.     runuser preinst
  942.  
  943.     #
  944.     # phase: inst
  945.     #
  946.  
  947.     # Live roboinst cannot go interactive on error because it is
  948.     # probably running as an "at" job.
  949.     onerror=`nawk '{ if ($1 != "") { print $1; exit} }' $MRCONFIG.onerror 2>&-`
  950.  
  951.     # inst will continue despite any errors
  952.     errflag="-Vabort_cmdfile_on_error:off"
  953.  
  954.     if [ "$onerror" = wait ]; then
  955.     $WARNING "cannot wait on error in live mode, \"onerror wait\" ignored"
  956.     fi
  957.  
  958.     if [ -s $MRCONFIG.inst ]; then
  959.     echo quit >> $MRCONFIG.inst
  960.     # execute inst, using the mrconfig.setenv.inst file
  961.     # that was determined during preprocessing
  962.     nocmd=0
  963.     if [ "$OSMAJ" -lt 6 ]; then
  964.         nocmd=1
  965.     elif [ "$OSMAJ" -eq 6 -a "$OSMIN" -lt 3 ]; then
  966.         nocmd=1
  967.     fi
  968.     if [ $nocmd = 1 ]; then
  969.         ( test -s $MRCONFIG.setenv.inst && . $MRCONFIG.setenv.inst;
  970.         /usr/sbin/inst -M -Vdist:none -Vinteractive:off $errflag -Vsyslog:on $* < $MRCONFIG.inst )
  971.     else
  972.         ( test -s $MRCONFIG.setenv.inst && . $MRCONFIG.setenv.inst;
  973.         /usr/sbin/inst -M -Vdist:none -c $MRCONFIG.inst -Vinteractive:off $errflag -Vsyslog:on $* )
  974.     fi
  975.     if [ $? = 0 ]; then
  976.         $LOGOK inst ok
  977.     else
  978.         $ERROR inst $? "Error occurred during software installation"
  979.     fi
  980.     fi
  981.     rm -f $TMPFILE 2>/dev/null
  982.  
  983.     #
  984.     # phase: postinst
  985.     #
  986.  
  987.     runuser postinst
  988.  
  989.     #
  990.     # done with roboinst processing, clean up
  991.     #
  992.  
  993.     $LOGOK done ok
  994.  
  995.     syslog_restore
  996.  
  997.     # clean up mrconfig directory
  998.  
  999.     if [ "$debugmode" != "debug" ]; then
  1000.       rm -fr $CUSTOM >/dev/null 2>&1
  1001.     fi
  1002.  
  1003.     exit 0
  1004. }
  1005.  
  1006. #------- functions for roboinst_start -------
  1007.  
  1008. # Send a log message to the tty, ignore all that syslog stuff
  1009.  
  1010. nologmsg()
  1011. {
  1012.     if [ "$1" = "ok" ]; then
  1013.         shift 2>/dev/null
  1014.     shift 2>/dev/null
  1015.         msg="$*"
  1016.     elif [ "$1" = "error" ]; then
  1017.         shift 2>/dev/null
  1018.         shift 2>/dev/null
  1019.     shift 2>/dev/null
  1020.         msg="error: $*"
  1021.     elif [ "$1" = "warning" ]; then
  1022.         shift 2>/dev/null
  1023.     msg="warning: $*"
  1024.     elif [ "$1" = "info" ]; then
  1025.         shift 2>/dev/null
  1026.     msg="$*"
  1027.     else
  1028.         msg="$*"
  1029.     fi
  1030.  
  1031.     $ECHO "$msg"
  1032. }
  1033.  
  1034. # Make sure prom rev $1.$2 is compatible (for O2 systems only)
  1035.  
  1036. checkrev()
  1037. {
  1038.     if [ "$1" = "" -o "$2" = "" ]; then
  1039.         echo "WARNING:  unable to determine PROM rev from hinv output"
  1040.         echo "WARNING:  roboinst requires PROM rev 4.4 or later on O2 systems"
  1041.     elif [ "$1" -lt 4 -o "$1" -eq 4 -a $2 -lt 4 ]; then
  1042.         $ERROR init 1 "roboinst requires PROM version 4.4 or later on O2 systems - install patch 2489 or successor"
  1043.         return 1
  1044.     fi
  1045.     return 0
  1046. }
  1047.  
  1048.  
  1049. # Determine whether the sash version X.Y in the specified volume
  1050. # header ($1) is the same version (or more recent) than the version
  1051. # specified ($2.$3).  Returns 0 if it is, or 1 if it is not.
  1052. # Sets SASHMAJ, SASHMIN and SASHMAINT variables as a side effect.
  1053.  
  1054. sashok()
  1055. {
  1056.     SASHMAJ=
  1057.     SASHMIN=
  1058.     SASHMAINT=
  1059.     eval `dvhtool -v g sash $TMPFILE $1 \
  1060.        && strings $TMPFILE \
  1061.       | nawk '{ if (match($0, "^.*Version +([0-9]+\.)([0-9]+)(\.[0-9]*)?.*$")) {
  1062.             sub("^.*Version +", "");
  1063.             match($0, "^([0-9]+\.)([0-9]+)(\.[0-9]*)?");
  1064.             split(substr($0, RSTART, RLENGTH), a, "\.");
  1065.             printf "SASHMAJ=%s; SASHMIN=%s; SASHMAINT=%s;\n", a[1], a[2], a[3];
  1066.             exit
  1067.              }
  1068.            }' 2>&- `
  1069.     rm -f $TMPFILE
  1070.     test "$SASHMAJ" -lt $2 -o \( "$SASHMAJ" -eq $2 -a "$SASHMIN" -lt $3 \) && return 1
  1071.     return 0
  1072. }
  1073.  
  1074.  
  1075. # Copy the sash from the vh of the first disk ($1) to
  1076. # the vh of the second disk ($2).
  1077.  
  1078. copysash()
  1079. {
  1080.     dvhtool -v get sash $TMPFILE $1 && dvhtool -v creat $TMPFILE sash $2
  1081.     STATUS=$?
  1082.     rm -f $TMPFILE
  1083.     return $STATUS
  1084. }
  1085.  
  1086.  
  1087. #
  1088. # ---- end of functions ----
  1089. #
  1090.  
  1091. #-------------- begin main processing -----------------------
  1092.  
  1093. # check if we think we're already robo pogo
  1094.  
  1095.     if [ -f $CHECKPOINT ]; then
  1096.     $WARNING "Canceling previously scheduled installation"
  1097.     if [ "$confirmation" != "no" ]; then
  1098.         rm $CHECKPOINT
  1099.     fi
  1100.     fi
  1101.  
  1102. # don't do prom and netaddr checks if running live
  1103.  
  1104. if [ "$livemode" != "yes" ]; then
  1105.  
  1106. # roboinst requires prom rev 4.4 or later on O2
  1107.  
  1108.     HSTATUS=0
  1109.     hinv >$TMPFILE 2>&-
  1110.     if grep 'IP32 Processor' $TMPFILE 1>&- 2>&- ; then
  1111.         PMAJ=
  1112.         PMIN=
  1113.         eval `sed -n 's/.*FLASH.*PROM.*version[ \t]*\([0-9]*\)\.\([0-9]*\)[ \t]*/PMAJ=\1; PMIN=\2;/p' $TMPFILE`
  1114.         checkrev "$PMAJ" "$PMIN"
  1115.         HSTATUS=$?
  1116.     fi
  1117.     rm $TMPFILE 2>&-
  1118.     test "$HSTATUS" = 0 || exit 1
  1119.  
  1120. # make sure nvram netaddr is sane, otherwise sash's bootp fails
  1121.  
  1122.     NETADDR=`nvram netaddr 2>&-`
  1123.     if [ "$NETADDR" = "192.0.2.1" ]; then
  1124.        $ERROR init 1 "roboinst requires that the nvram netaddr variable be set to the"
  1125.        $ERROR init 1 "appropriate value for this machine.  Please set it using the"
  1126.        $ERROR init 1 "nvram(1M) command."
  1127.     fi
  1128.  
  1129.  
  1130. # need to map the nvram variable formats:
  1131. #     *scsi(N)disk(M)rdisk(*)partition(P)
  1132. #     dksc(N,M,P)
  1133. # to the filesystem formats:
  1134. #     /dev/rdsk/dksNdMvh
  1135. #     /dev/dsk/dksNdMsP
  1136. # NOTE: assumes that the existing values are valid, or will set garbage!
  1137.  
  1138.     $DEBUG "syspart= $syspart"
  1139.     case "$syspart" in
  1140.     "")
  1141.         # let dvhtool use the default
  1142.         SYSPART=""
  1143.         ;;
  1144.     yes|y)
  1145.         # use what's in nvram
  1146.         nvsyspart=`nvram SystemPartition`
  1147.         SYSPART=`echo "$nvsyspart" | sed -n \
  1148.             -e 's%^dksc(\([0-9]*\),\([0-9]*\),[0-9a-fA-F]*)%/dev/rdsk/dks\1d\2vh%p' \
  1149.             -e 's%^.*scsi(\([0-9]*\))disk(\([0-9]*\))rdisk(.*)partition(.*)$%/dev/rdsk/dks\1d\2vh%p'`
  1150.         $DEBUG "nvsyspart= $nvsyspart"
  1151.         ;;
  1152.     [0-9]|[0-9][0-9])
  1153.         # disk only change, edit the nvram vars
  1154.         nvsyspart=`nvram SystemPartition`
  1155.         if [ "$confirmation" != "no" ]; then
  1156.         nvram SystemPartition `echo "$nvsyspart" | sed -n \
  1157.             -e "s/^dksc(\([0-9]*\),.*$/dksc(\1,${syspart},8)/p" \
  1158.             -e "s/disk([^)]*)/disk(${syspart})/p"`
  1159.         $DEBUG "nvsyspart= $nvsyspart => `nvram SystemPartition`"
  1160.         nvloadpart=`nvram OSLoadPartition`
  1161.         nvram OSLoadPartition `echo "$nvloadpart" | sed -n \
  1162.             -e "s/^dksc(\([0-9]*\),[0-9]*,\([0-9a-fA-F]*\))$/dksc(\1,${syspart},\2)/p" \
  1163.             -e "s/disk([^)]*)/disk(${syspart})/p"`
  1164.         $DEBUG "nvloadpart= $nvloadpart => `nvram OSLoadPartition`"
  1165.         nvroot=`nvram root 2> /dev/null`
  1166.         nvram root `echo $nvroot | sed -e 's/dks\([0-9]*\)d[0-9]*s\([0-9]*\)/dks\1d'${syspart}'s\2/'` 2>/dev/null
  1167.         $DEBUG "nvroot= $nvroot => `nvram root`"
  1168.         fi
  1169.         sysbuss=`echo $nvsyspart | sed -n \
  1170.             -e 's/^.*scsi(\([0-9]*\))disk.*$/\1/p' \
  1171.             -e 's/^dksc(\([0-9]*\),[0-9]*,[0-9]*)$/\1/p`
  1172.         SYSPART="/dev/rdsk/dks${sysbuss}d${syspart}vh"
  1173.         ;;
  1174.     dksc\(*\))
  1175.         # this is OSLoadPartition, assumed valid syntax for this system
  1176.         SYSPART=`echo "$syspart" | sed \
  1177.             -e 's%^dksc(\([0-9]*\),\([0-9]*\),.*)$%/dev/rdsk/dks\1d\2vh/%'`
  1178.         if [ "$confirmation" != "no" ]; then
  1179.         nvram SystemPartition `echo "$syspart" | sed -e 's/,[0-9a-fA-F]*)$/,8)/'`
  1180.         nvram OSLoadPartition  "$syspart"
  1181.         nvram root `echo $syspart | sed \
  1182.             -e 's/dksc(\([0-9]*\),\([0-9]*\),\([0-9]*\))/dks\1d\2s\3/'` 2>/dev/null
  1183.         $DEBUG "root => `nvram root`"
  1184.         fi
  1185.         $DEBUG "syspart= $syspart"
  1186.         ;;
  1187.     [a-z]*\))
  1188.         # this is OSLoadPartition, assumed valid syntax for this system
  1189.         SYSPART=`echo $syspart | sed \
  1190.             -e 's%^.*scsi(\([0-9]*\))disk(\([0-9]*\))rdisk(.*)partition(.*)$%/dev/rdsk/dks\1d\2vh%'`
  1191.         if [ "$confirmation" != "no" ]; then
  1192.         nvram SystemPartition `echo "$syspart" | sed -e 's/([^(]*)$/(8)/'`
  1193.         nvram OSLoadPartition  "$syspart"
  1194.         nvram root `echo $syspart | sed \
  1195.             -e 's%^.*scsi(\([0-9]*\))disk(\([0-9]*\))rdisk(.*)partition(\([0-9]*\))$%dks\1d\2s\3%'` 2>/dev/null
  1196.         $DEBUG "root => `nvram root`"
  1197.         fi
  1198.         $DEBUG "syspart= $syspart"
  1199.         ;;
  1200.     *)
  1201.         # badly formatted?
  1202.         $ERROR init 1 "badly formatted OSLoadPartition value: \"${syspart}\""
  1203.         SYSPART=""
  1204.         exit 1
  1205.         ;;
  1206.     esac
  1207.     $DEBUG "SYSPART= $SYSPART"
  1208.  
  1209. # make sure sash is 6.5 or later, otherwise the miniroot boot will fail
  1210.  
  1211.     badsash=""
  1212.     if sashok "$SYSPART" 6 5 ; then
  1213.  
  1214.     # 6.5 or later sash is in vh of disk we'll be booting
  1215.     # the miniroot from
  1216.     $DEBUG "booting with sash rev $SASHMAJ.$SASHMIN"
  1217.  
  1218.     elif test "$SYSPART" != "" && \
  1219.      test "`/sbin/stat -iq /dev/rvh`" != "`/sbin/stat -iq $SYSPART`" && \
  1220.      sashok /dev/rvh 6 5 ; then
  1221.  
  1222.     # This is an alternate disk install (-P) onto a disk other than
  1223.     # the root drive, and there is a usable sash in the root volhdr.
  1224.     # If it's not a dryrun, copy sash from root disk to alternate disk
  1225.  
  1226.     if [ "$confirmation" != no ]; then
  1227.         if copysash /dev/rvh "$SYSPART" && sashok "$SYSPART" 6 5 ; then
  1228.         # Booting miniroot onto an alternate disk (not the root drive),
  1229.         # and we successfully copied a recent sash from the root vh
  1230.         # to the vh of the other disk.
  1231.         $DEBUG "copied sash rev $SASHMAJ.$SASHMIN from root vh to $SYSPART"
  1232.         else
  1233.         # Copy failed
  1234.         badsash=1
  1235.         fi
  1236.     else
  1237.         $DEBUG "would copy sash rev $SASHMAJ.$SASHMIN from root vh to $SYSPART"
  1238.     fi
  1239.     else
  1240.     # No usable sash found on root or alternate disk
  1241.     badsash=1
  1242.     fi
  1243.  
  1244.     if [ "$badsash" = 1 ]; then
  1245.     $ERROR init 1 "The correct version of sash does not appear to be installed"
  1246.     $ERROR init 1 "in the volume header.  Roboinst miniroot installations require"
  1247.     $ERROR init 1 "an IRIX 6.5 or later version of sash.  Install the roboinst"
  1248.     $ERROR init 1 "client software on the target machine and see the discussion of"
  1249.     $ERROR init 1 "the -P option in the roboinst(1M) manual page."
  1250.     exit 1
  1251.     fi
  1252.  
  1253. fi
  1254.  
  1255. OSMAJ=""
  1256. OSMIN=""
  1257. eval `uname -r | sed -n 's/^\([0-9]*\)\.\([0-9]*\).*/OSMAJ=\1; OSMIN=\2;/p' 2>&-`
  1258. OSVER="$OSMAJ.$OSMIN"
  1259.  
  1260. if [ "$bootdir" != "" ]; then
  1261.  
  1262. # get CPUBOARD to discover which sash to boot from
  1263.  
  1264.     mkdir -p $TMPROOT/var/inst
  1265.     touch $TMPROOT/var/inst/hist
  1266.     ln -s $rbase/var/inst/roboinst $TMPROOT/var/inst/roboinst
  1267.     echo admin hardware | /usr/sbin/inst -f none -r $TMPROOT -Vmenus:off 2>&1 > $TMPFILE
  1268.     egrep '^CPUBOARD=|^MODE=' $TMPFILE > $TMPROOT/adminhw
  1269.     cpu=`sed -n 's/^CPUBOARD=//p' $TMPROOT/adminhw | head -1`
  1270.     mode=`sed -n 's/^MODE=//p' $TMPROOT/adminhw | head -1`
  1271.     rm -rf $TMPROOT
  1272.     # On 5.3 systems mode is implicitly 32bit
  1273.     if [ "$cpu" != "" -a "$mode" = "" -a "$OSVER" = 5.3 ]; then
  1274.         mode=32bit
  1275.     fi
  1276.  
  1277.     if [ "$cpu" = "" -o "$mode" = "" ]; then
  1278.     while read tmpline; do
  1279.         $ERROR init 1 "$tmpline"
  1280.     done < $TMPFILE
  1281.     $ERROR init 1 "Cannot determine hardware CPUBOARD and MODE, and as a"
  1282.     $ERROR init 1 "result cannot determine whether to use the 32-bit sash"
  1283.     $ERROR init 1 "or 64-bit sash to boot the miniroot environment - aborting."
  1284.     $ERROR init 1 "Check to make sure that the inst program is functional."
  1285.     rm -f $TMPFILE
  1286.     abort 1
  1287.     fi
  1288.     rm -f $TMPFILE
  1289.  
  1290.     if [ "$mode" = "32bit" -o "$cpu" = "IP19" ]; then
  1291.      promtype="sashARCS";
  1292.     else
  1293.      promtype="sash64";
  1294.     fi
  1295.  
  1296.     $DEBUG "Using promtype $promtype"
  1297.  
  1298. fi
  1299.  
  1300. # get IP address of bootserver and configserver
  1301.  
  1302.     confighost=`echo $configdir | nawk -F: '{print $1}'`
  1303.     configpath=`echo $configdir | sed -e 's/^[^:]*://' -e 's|/$||'`
  1304.  
  1305.     getipaddr $confighost
  1306.     if [ "$IPADDR" = "0" ]; then
  1307.     $ERROR init 1 "Unable to get IP address for configserver $confighost, aborting"
  1308.     exit 1
  1309.     fi
  1310.     confighostip=$IPADDR
  1311.  
  1312.     $DEBUG configserverIP $confighostip
  1313.  
  1314. # don't do bootfile and miniroot kernel checks if running live
  1315.  
  1316. if [ "$bootdir" != "" ]; then
  1317.  
  1318. # Determine if bootfile and miniroot kernel exist
  1319.  
  1320.     boothost=`echo $bootdir | nawk -F: '{print $1}'`
  1321.     bootpath=`echo $bootdir | sed -e 's/^[^:]*://' -e 's|/$||'`
  1322.  
  1323.     bootsa=$bootpath/sa
  1324.     bootunix=$bootpath/miniroot/unix.$cpu
  1325.  
  1326.     if [ -x $BPCLT ]; then
  1327.     bpsa=`$BPCLT -b $boothost:$bootsa | sed -n 's/^file=//p'`
  1328.     bpunix=`$BPCLT -b $boothost:$bootunix | sed -n 's/^file=//p'`
  1329.     else
  1330.     $ERROR init 1 "$BPCLT not installed, aborting"
  1331.     exit 1
  1332.     fi
  1333.  
  1334.     if [ "$bpsa" != "$bootsa" ]; then
  1335.     $ERROR init 1 "Unable to read bootfile $boothost:$bootsa, aborting"
  1336.     exit 1
  1337.     fi
  1338.     if [ "$bpunix" != "$bootunix" ]; then
  1339.     $ERROR init 1 "Unable to read kernel $boothost:$bootunix, aborting"
  1340.     exit 1
  1341.     fi
  1342.  
  1343. fi
  1344.  
  1345. # get the configuration files
  1346.  
  1347.     get_config
  1348.  
  1349.     # check logging
  1350.     loghost=`cat $MRCONFIG.loghost 2>&-`
  1351.     $DEBUG "mrconfig loghost is $loghost"
  1352.  
  1353.     if [ -f $MRCONFIG.disksetup ]; then
  1354.     disksetup="disksetup"
  1355.     $DEBUG "mrconfig disksetup"
  1356.     fi
  1357.  
  1358. # clean up
  1359.  
  1360.     rm -fr $CUSTOM >/dev/null 2>&1
  1361.  
  1362.     if [ "$disksetup" = "disksetup" ]; then
  1363.     disksetup="disksetup=true"
  1364.     fi
  1365.  
  1366. # get IP address of loghost
  1367.  
  1368.     if [ "$loghost" = "" ]; then
  1369.     $ERROR init 1 "loghost not set in $configdir/mrconfig,"
  1370.     $ERROR init 1 " logging will be local-only"
  1371.     fi
  1372.  
  1373.     getipaddr `hostname`
  1374.     thisip=$IPADDR
  1375.     loghostip=""
  1376.  
  1377.     for host in $loghost ; do
  1378.     if [ "$host" = "localhost" ]; then
  1379.         IPADDR=$thisip
  1380.     else
  1381.         getipaddr $host
  1382.     fi
  1383.     if [ "$IPADDR" = "0" ]; then
  1384.         $ERROR init 1 "Unable to get IP address for loghost $host, aborting"
  1385.         exit 1
  1386.     fi
  1387.     loghostip="$loghostip $IPADDR"
  1388.     done
  1389.  
  1390.     $DEBUG "loghostip $loghostip"
  1391.  
  1392. # okay, everything looks good
  1393.  
  1394.     if [ "$reportaddr" = "yes" ]; then
  1395.     $ECHO "roboinst: PROMIFADDR -z $chaddr"
  1396.     fi
  1397.  
  1398. # let's confirm
  1399.  
  1400.     if [ "$confirmation" = "" ]; then
  1401.  
  1402.     if [ "$livemode" != "yes" ]; then
  1403.         ask "`gettxt ${msgfile}:1166 'Do you want to continue with the shutdown and proceed with\nautomatic miniroot installation? '`" 0
  1404.     else
  1405.         ask "`gettxt ${msgfile}:1167 'Do you want to continue with the automatic installation? '`" 0
  1406.     fi
  1407.     
  1408.     if [ $? -eq 0 ]; then
  1409.         confirmation=no
  1410.     else
  1411.         confirmation=yes
  1412.     fi
  1413.     fi
  1414.  
  1415. # if not confirmed, this is a dryrun
  1416.  
  1417.     if [ "$confirmation" = "no" ]; then
  1418.     timestr=""
  1419.     fi
  1420.  
  1421. # submit the job if a time was specified, otherwise take the machine DOWN:
  1422. # 1) create file in /var/inst to indicate robo has been requested
  1423. # 2) create file in volume header for roboinst
  1424.  
  1425.     if [ "$timestr" != "" ]; then
  1426.  
  1427.     liveopt=""
  1428.     bootopt=""
  1429.     if [ "$livemode" = "yes" ]; then
  1430.         liveopt="-L"
  1431.     fi
  1432.  
  1433.     if [ "$bootdir" != "" ]; then
  1434.         bootopt="-b $bootdir"
  1435.     fi
  1436.  
  1437.     # If an email address was specified, output goes there,
  1438.     # otherwise quash all output so at doesn't send email.
  1439.     if [ "$emailaddr" = "" ]; then
  1440.         filter="1>&- 2>&-"
  1441.     else
  1442.         filter="2>&1 | /usr/sbin/Mail -s \"roboinst job completed\" $emailaddr"
  1443.     fi
  1444.  
  1445. # + 1 minute is because 6.2/5.3 at now does not work
  1446.  
  1447.     nocmd=0
  1448.     if [ "$OSMAJ" -lt 6 ]; then
  1449.         nocmd=1
  1450.     elif [ "$OSMAJ" -eq 6 -a "$OSMIN" -lt 5 ]; then
  1451.         nocmd=1
  1452.     fi
  1453.     if [ $nocmd = 1 -a "$timestr" = "now" ]; then
  1454.         timestr="$timestr + 1 minute"
  1455.     fi
  1456.     
  1457.     atcmd="/bin/sh $0 -y $liveopt -c $confighostip:$configpath $bootopt $filter"
  1458.     $DEBUG "scheduling $atcmd"
  1459.     ( echo "$atcmd" | /usr/bin/at $timestr 2>&1 &&
  1460.         $ECHO "Automatic installation scheduled for $timestr" ) \
  1461.     | grep -v executed
  1462.  
  1463.     else
  1464.  
  1465. # if we're running live, don't set up volume header and reboot
  1466.  
  1467.     if [ "$livemode" = "yes" ]; then
  1468.         runlive
  1469.         exit 0
  1470.     fi
  1471.  
  1472. # need to rebuild bootfile in terms of IP address
  1473.  
  1474.     TAPEDEV="bootp()$boothost:$bootsa"
  1475.     BOOTFROM="$TAPEDEV($promtype)"
  1476.  
  1477. # need to parse out IP address for dlserver
  1478.  
  1479.     cat <<EOF > $TMPFILE
  1480. 0
  1481. BOOTARGS=mrmode=custom$debugmode $disksetup
  1482. BOOTFILE=$BOOTFROM
  1483. ENV:tapedevice=$TAPEDEV
  1484. ENV:dlserver=$boothost
  1485. ENV:mrconfig=$configdhcp$confighostip:$configpath
  1486. ENV:netaddr=$netaddr
  1487. ENV:netmask=$netmask
  1488. EOF
  1489.  
  1490.     if [ "$confirmation" = "no" ]; then
  1491.  
  1492.         if [ "$debugmode" = "debug" ]; then
  1493.         $DEBUG "auto_mr:"
  1494.         cat $TMPFILE
  1495.         rm -f $TMPFILE > /dev/null 2>&1
  1496.         fi
  1497.  
  1498.         $ECHO "Automatic installation canceled"
  1499.         exit 1
  1500.     fi
  1501.  
  1502.     cat <<EOF > $CHECKPOINT
  1503. #! /bin/sh
  1504. #Tag 0x00000f00
  1505.  
  1506. # $CHECKPOINT
  1507. # created by roboinst_start
  1508. # version $DEFVERS
  1509.  
  1510. LOGHOST="$loghostip"
  1511.  
  1512. cp /etc/syslog.conf /etc/syslog.conf.new.\$\$ 2>&-
  1513.  
  1514.     for HOST in \$LOGHOST ; do
  1515.         echo '*.debug;kern,syslog.none    @'\$HOST >> /etc/syslog.conf.new.\$\$
  1516.     done
  1517.  
  1518. cp /etc/syslog.conf /etc/syslog.conf.old.\$\$
  1519. mv /etc/syslog.conf.new.\$\$ /etc/syslog.conf
  1520. killall -HUP syslogd
  1521. logger -t roboinst "state=start status=1 error: failed to reach miniroot state"
  1522. mv /etc/syslog.conf.old.\$\$ /etc/syslog.conf
  1523. killall -HUP syslogd
  1524. EOF
  1525.     chmod +x $CHECKPOINT
  1526.  
  1527. # now stuff the volume header and restart
  1528.     /sbin/dvhtool -v creat $TMPFILE auto_mr $SYSPART 2>&1
  1529.  
  1530.     if [ $? != 0 ]; then
  1531.         rm -f $CHECKPOINT $TMPFILE > /dev/null 2>&1
  1532.         $ECHO "Automatic installation did not start, dvhtool error"
  1533.         exit 1
  1534.     fi
  1535.  
  1536.         rm -f $TMPFILE > /dev/null 2>&1
  1537.  
  1538.     if [ "$loghost" != "" ]; then
  1539.         syslog_addhost $loghost
  1540.         logger -t roboinst "state=start status=0 restarting for automatic installation"
  1541.         syslog_restore
  1542.     fi
  1543.  
  1544.     $ECHO "Automatic installation started"
  1545.  
  1546.     if [ -x /etc/shutdown ] ; then
  1547.         echo "3" | /etc/shutdown -y -i6 -g$grace
  1548.     else
  1549.         echo "3" | /sbin/init 6
  1550.     fi
  1551.  
  1552.     fi
  1553.